package com.boot2.core.utils;

import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author LiuJie
 * @date 2016年4月15日 下午3:22:07
 * @version V1.0
 * @description 多线程分发工具类
 */
public class RunnableUtil
{
    /**
     * @Fields POOL_SIZE : 线程池大小
     */
    private final static int POOL_SIZE = 10;

    /**
     * @Fields FIX_PARAMETER : 固定的参数个数
     */
    private static final int FIX_PARAMETER_COUNT = 2;

    /**
     * @description
     * @param clazz
     *            被调用的线程实现类
     * @param list
     *            需要执行的结果集
     * @param objects
     *            ...（可变参数）线程需要用到的参数，没有传null
     * @return void
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     */
    public static void executorBlock(Class<? extends Runnable> clazz, List<?> list, Object... objects)
    {
        Constructor<?>[] constructors = clazz.getConstructors();
        Class<?>[] paraArr = constructors[0].getParameterTypes();

        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        ThreadPoolExecutor exe = (ThreadPoolExecutor) pool;
        System.out.println(exe.getPoolSize());
        for (int i = 0; i < list.size(); i++)
        {
            // 每一段的开始索引
            Runnable runnable = null;
            try
            {
                // 大于2个就是内部类需要传内部类的实例
                if (paraArr.length > FIX_PARAMETER_COUNT)
                    runnable = (Runnable) constructors[0].newInstance(null, list.get(i), objects);
                else
                    runnable = (Runnable) constructors[0].newInstance(list.get(i), objects);
            }
            catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
            {
                e.printStackTrace();
            }

            pool.submit(runnable);
        }
        pool.shutdown();
    }

    public static void executeThreadPool(Class<? extends Runnable> clazz, List<?> list, Object... objects) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException
    {
        ThreadPoolExecutor cachedThreadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
        executeThreadPool(cachedThreadPool, clazz, list, objects);
    }

    public static void executeThreadPool(Class<? extends Runnable> clazz, List<?> list, int poolSize, Object... objects) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException
    {
        ThreadPoolExecutor cachedThreadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize);
        executeThreadPool(cachedThreadPool, clazz, list, objects);
    }

    private static void executeThreadPool(ThreadPoolExecutor cachedThreadPool, Class<? extends Runnable> clazz, List<?> list, Object... objects) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException
    {
        for (int i = 0; i < list.size(); i++)
        {
            Runnable runnable = null;
            try
            {
                // call = (Callable<?>) SpringContextUtil.createBean(clazz);
                runnable = (Runnable) ConstructorUtils.invokeConstructor(clazz, list.get(i), objects);
            }
            catch (IllegalArgumentException e)
            {
                e.printStackTrace();
            }
            cachedThreadPool.submit(runnable);
        }
        cachedThreadPool.shutdown();
    }

    @Test
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<>(99999);
        for (int i = 0; i < 9999; i++) {
            list.add("线程_"+i);
        }
        System.out.println("list: "+list.size());
        Map<String, Object> map = new HashMap<>();
        map.put("name", "zhangsan");
        ThreadPoolTaskExecutorUtil.executorBlock(MyThread.class, list);
    }

}



class MyThread implements Runnable
{

    private String str;
    private Object[] objects;

    public MyThread(String str, Object[] objects)
    {
        this.str = str;
        this.objects = objects;
    }

    @Override
    public void run()
    {
        System.out.println("str" + "=" + str);
        System.out.println(objects[0]);
        System.out.println(objects[1]);
        // try
        // {
        // Thread.sleep(500);
        // }
        // catch (InterruptedException e)
        // {
        // // TODO Auto-generated catch block
        // e.printStackTrace();
        // }
    }

}
